package com.msun.auth.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.Map;
import java.util.UUID;


public final class JwtUtils {
    private static final String saltKey = "salt";

    public static final String tokenSalt = "Fv46G5yGhNnIpOQ9";

    public static String createToken(Map<String, Object> claims, String key, String subject, Long ttlMillis) {
        if (claims == null) {
            return "";
        }
        if (ttlMillis == null) ttlMillis = 2592000000L;
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        claims.put(saltKey, tokenSalt);
        JwtBuilder builder = Jwts.builder()
                //如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .setClaims(claims)
                //设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setId(UUID.randomUUID().toString())
                //iat: jwt的签发时间
                .setIssuedAt(now)
                //代表这个JWT的主体，即它的所有人，这个是一个json格式的字符串，可以存放什么userid，roldid之类的，作为什么用户的唯一标志。
                .setSubject(subject)
                //设置签名使用的签名算法和签名使用的秘钥
                .signWith(signatureAlgorithm, key);
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            //设置过期时间
            builder.setExpiration(exp);
        }
        return AesUtils.encrypt(builder.compact(), key);
    }

    public static Map<String, Object> parseToken(String token, String key) throws Exception {
        token = AesUtils.decrypt(token, key);
        Claims claims = Jwts.parser()
                //设置签名的秘钥
                .setSigningKey(key)
                //设置需要解析的jwt
                .parseClaimsJws(token).getBody();
        if (!StringUtils.equals(tokenSalt, String.valueOf(claims.get(saltKey)))) {
            throw new Exception("非法签名");
        }
        if (claims.getExpiration().before(new Date())) {
            throw new Exception("签名已过期");
        }
        return claims;
    }
}
